#!/usr/bin/python3
# coding:utf-8
import sys
import threading
import subprocess
import time
from queue import Queue
from optparse import OptionParser

# 初始化变量，ipSucess为存储可以ping通的IP列表，Work_Thread为后台工作进程数，ipQueue为执行命令的队列
ipSuccess = []
Work_Thread = 254
ipQueue = Queue()


def main(a):
    start_time = time.time()
    # 初始化列表，主要用来存放渲染为绿色的IP信息，"\033[92m \033[0m"
    ip_p = []

    # 默认全部渲染为灰色，同时因为x.x.x.0/24为网络号，无实质意义，替换为空
    for i in range(0, 255):
        t = '\033[90m' + str(i) + '\033[0m'
        ip_p.append(t)
    ip_p[0] = '\033[91m' + '' + '\033[0m'

    # 判断命令行参数-n 或 --net后的字符串是否符合要求，此处判断存在漏洞，需完善
    if len(a) > 0 and len(a.split('.')) == 4 and a.split('.')[-1] == '':
        # 拼接符合要求的数据并放入队列
        for i in range(1, 255):
            ipQueue.put(a + str(i))

        # 初始化线程池，并多线程调用pingIP函数
        threads = []
        for i in range(Work_Thread):
            thread = threading.Thread(target=pingIp)
            thread.start()
            threads.append(thread)
        for thread in threads:
            thread.join()

        # 将可以ping通的IP地址从ipsuccess列表取出并渲染成绿色
        for i in ipSuccess:
            # print(i)
            ip_p[int(i.split('.')[-1])] = '\033[92m' + \
                i.split('.')[-1] + '\033[0m'

        # 该函数定制最终输出内容的格式，每行16个IP，一共16行，其中0和254去除
        def ip_info(ip_p):
            print("Ping Results:")
            n = 16
            for i in range(len(ip_p)):

                print('{0:>12}'.format(ip_p[i]), end=' '*2)
                if (i + 1) % n == 0:
                    print('\n', end='')

        # 将渲染后的结果进行打印
        ip_info(ip_p)

        # 打印提示信息，包括在线主机数和脚本执行时间
        time_info = format(time.time() - start_time, '.2f')
        run_info = a + '在线数:' + \
            str(len(ipSuccess)) + '\t' + '执行耗时:' + time_info + 's'
        print('\n' + run_info)

        # 释放无用资源
        ipSuccess.clear()
        ip_p.clear()
    else:
        # 打印cli提示信息
        parser.print_help()

# 多线程执行命令，并构建ipsuccess列表


def pingIp():
    while not ipQueue.empty():
        ip = ipQueue.get()
        # 如果为linux或macos，此处cmd应为'ping -c 2 -W 5',命令行参数不太一致
        cmd = 'ping -n 2 -w 5 %s' % ip
        # 如果为linux或macos，此处subprocess.call参数需在后面补充shell=True
        DETACHED_PROCESS = 0x00000008
        p = subprocess.call(cmd, stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE, creationflags=DETACHED_PROCESS)
        # print(ip, True if res == 0 else False)
        # 如果返回值为0，代表ping命令正确返回，此处仅简单判断状态，后续可读取通道信息，获取延时数据，针对延时时长渲染其他的颜色
        if p == 0:
            ipSuccess.append(ip)


# 从这里开始执行
if __name__ == '__main__':
    # 构建命令行参数
    parser = OptionParser()
    # 本行新增-n或--net参数，参数赋值于变量net
    parser.add_option("-n", "--net",
                      help="for example: ping_cli.py -n 192.168.1.", metavar="net")
    (options, args) = parser.parse_args()
    if options.net != None:
        # 把命令行变量net传给main函数并执行
        main(options.net)
    else:
        # 无法正确获得命令行参数时打印帮助信息并退出程序
        parser.print_help()
